package move_system

import (
	"confs/gen/common"
	"confs/gen/gd"
	"confs/gen/rpc_protos"
	"errors"
	"game/app/actors"
	"game/app/actors/schemas"
	"game/app/handlers/helpers/rpc_helper"
	"game/app/systems/map_system"
	"game/app/systems/math_system/math_defines"
	"game/app/systems/math_system/math_utils"
	"game/app/systems/move_system/move_defines"
	"game/app/systems/move_system/move_utils"
	"gos/bases/parse"
	"gos/bases/time_tools"
	"gos/modules/logger"
	"gos/services/gactor/actor"
	"sort"
)

func init() {
	actors.RegisterMoveTicker("move_update", Move.TickerMoveRefresh)
	actors.RegisterDitryTicker("move_ditry_update", Move.DitryTickerRefresh)
}

// MoveSystem 移动系统
type MoveSystem struct{}

type IMoveSystem interface {
	Find(state *schemas.MoveState, id int64) *schemas.MoveEntity
	// Register
	Register(state *schemas.MoveState, entity *common.MoveEntity) *schemas.MoveEntity
	// UnRegister
	UnRegister(state *schemas.MoveState, id int64) *schemas.MoveEntity
	// CreateEntity
	CreateEntity(state *schemas.MoveState, entity *common.MoveEntity) *schemas.MoveEntity
	// TickerMoveRefresh
	TickerMoveRefresh(state *schemas.MoveState) error
	// DitryTickerRefresh
	DitryTickerRefresh(state *schemas.MoveState) error
	// MoveFollow
	MoveFollow(state *schemas.MoveState, entity *schemas.MoveEntity, targetEntity *schemas.MoveEntity,
		cb1 func(done bool, reason int32, value any),
		cb2 func(done bool, reason int32) bool) error
	// StopFollow
	StopFollow(state *schemas.MoveState, entity *schemas.MoveEntity)
	// CheckMoveTo
	CheckMoveTo(state *schemas.MoveState, pos math_utils.Vector2D) bool
	// MoveTo
	MoveTo(state *schemas.MoveState, entity *schemas.MoveEntity, targetPos *common.Vector2D, cb1 func(done bool, reason int32, value any),
		cb2 func(done bool, reason int32) bool) error
	// ChangeSpeed
	ChangeSpeed(state *schemas.MoveState, speed int32)
	// StopMove
	StopMove(state *schemas.MoveState, entity *schemas.MoveEntity, reason int32)
	// RpcGetMoveEntity
	RpcGetMoveEntity(serverId, id int64) (*common.MoveData, bool)
	// FindAndUpdate
	FindAndUpdate(state *schemas.MoveState, id int64) *schemas.MoveEntity
	//IsMoveCircle
	IsMoveCircle(state *schemas.MoveState, entity *schemas.MoveEntity) bool
	// IsMoving
	IsMoving(state *schemas.MoveState, entity *schemas.MoveEntity) bool
	// IsMoveNone
	IsMoveNone(state *schemas.MoveState, entity *schemas.MoveEntity) bool
	// CalFollowPos
	CalcFollowPos(state *schemas.MoveState, entity *schemas.MoveEntity, targetEntity *schemas.MoveEntity) *common.Vector2D
}

var Move IMoveSystem = MoveSystem{}

// StopFollow
func (m MoveSystem) StopFollow(state *schemas.MoveState, entity *schemas.MoveEntity) {
	mapAIEntities, ok := state.GetTargetBattleAIEntity(entity.Id)
	if !ok {
		// 说明当前没有敌人正在追击自己
		return
	}

	logger.WARN("结束当前正在追击自己的敌人:", mapAIEntities)
	for _, id := range mapAIEntities {
		followEntity := state.GetMoving(id)
		if followEntity == nil {
			logger.ERR("结束战斗 无法找到正在追我的追击实体:", id)
			return
		}

		// 让正在追击的人停止移动
		if !m.IsMoveNone(state, followEntity) {
			m.StopMove(state, followEntity, move_defines.StopMoveReasonStopCommand)
		} else {
			m.onStopMove(state, followEntity, false, move_defines.StopMoveReasonStopCommand)
		}
	}
}

// UnRegister
func (m MoveSystem) UnRegister(state *schemas.MoveState, id int64) *schemas.MoveEntity {
	entity := state.GetMoving(id)
	if entity != nil {
		state.DeleteMoving(id)
		return entity
	} else {
		return nil
	}
}

// Register 注册实体
func (m MoveSystem) Register(state *schemas.MoveState, entity *common.MoveEntity) *schemas.MoveEntity {
	logger.WARN("Register id:", entity.Id)
	if state.GetMoving(entity.Id) == nil {
		moveEntity := schemas.NewMoveEntity(entity)
		state.AddMoving(moveEntity.Id, moveEntity)
		return moveEntity
	} else {
		return nil
	}
}

// Find
func (m MoveSystem) Find(state *schemas.MoveState, id int64) *schemas.MoveEntity {
	entity := state.GetMoving(id)
	if entity == nil {
		return nil
	}
	return entity
}

// CreateAndUpdate 创建移动和更新移动
func (m MoveSystem) CreateEntity(state *schemas.MoveState, entity *common.MoveEntity) *schemas.MoveEntity {
	// 获取最新的坐标
	// 需要等待移动寻路成功后，才将实体注册
	moveEntity := state.GetMoving(entity.Id)
	if moveEntity != nil {
		if m.IsMoveCircle(state, moveEntity) || m.IsMoving(state, moveEntity) {
			m.updateMove(state, moveEntity)
		}
		// 如果存在实体就复用
		m.clear(state, moveEntity)
		moveEntity.Update(entity)
		return moveEntity
	} else {
		return m.Register(state, entity)
	}
}

// FindAndUpdate 查找最新坐标
func (m MoveSystem) FindAndUpdate(state *schemas.MoveState, id int64) *schemas.MoveEntity {
	entity := state.GetMoving(id)
	if entity != nil {
		if m.IsMoveCircle(state, entity) || m.IsMoving(state, entity) {
			m.updateMove(state, entity)
		}
		return entity
	} else {
		return nil
	}
}

// isMoveCricle 移动绕城堡中
func (m MoveSystem) IsMoveCircle(state *schemas.MoveState, entity *schemas.MoveEntity) bool {
	return entity.MoveStatus == common.MoveStatusType_MoveStatusMoveCircle
}

// isMoving 移动中
func (m MoveSystem) IsMoving(state *schemas.MoveState, entity *schemas.MoveEntity) bool {
	return entity.MoveStatus == common.MoveStatusType_MoveStatusMoving
}

// isMoveNone
func (m MoveSystem) IsMoveNone(state *schemas.MoveState, entity *schemas.MoveEntity) bool {
	return entity.MoveStatus == common.MoveStatusType_MoveStatusNone
}

// UpdateMove 更新移动最新坐标
func (m MoveSystem) updateMove(state *schemas.MoveState, entity *schemas.MoveEntity) {
	if m.IsMoveNone(state, entity) {
		return
	}
	m.handleMove(state, entity)
}

// StopMove 停止移动
func (m MoveSystem) StopMove(state *schemas.MoveState, entity *schemas.MoveEntity, reason int32) {
	if m.IsMoveNone(state, entity) {
		return
	}

	m.updateMove(state, entity)
	m.onStopMove(state, entity, false, reason)
}

// setPropertyDirty 设置移动脏数据，用于批量同步proto
func (m MoveSystem) setPropertyDirty(entity *schemas.MoveEntity, typ common.MovePropertyType) {
	entity.Ditry[typ].IsDitry = true
	entity.Ditry[typ].Type = typ
	entity.IsDitry = true
}

func (m MoveSystem) clear(state *schemas.MoveState, entity *schemas.MoveEntity) {
	entity.MoveStatus = common.MoveStatusType_MoveStatusNone
	entity.MoveCallback = nil
	// entity.FollowTargetPos = math_utils.Vector2D{}
	// entity.FollowTargetPos = math_utils.Vector2D{}
	// entity.FollowTargetId = 0
	// entity.ResetTick = 0
	// entity.IsNotice = false
	// entity.IsFollowed = false
	entity.IsFollowMove = false

	entity.IsDitry = false
	entity.Rout = false
	entity.PreCheckTime = 0
	entity.Paths = []math_utils.Vector2D{}
	entity.MoveCirclePaths = []math_utils.Vector2D{}
	entity.MovePathData = []*common.Vector2D{}
}

// onStopMove 被动停止移动
func (m MoveSystem) onStopMove(state *schemas.MoveState, entity *schemas.MoveEntity, done bool, reason int32) {
	if entity.IsFollowMove && done {
		entity.IsFollowed = false
		return
	}

	var status bool
	if entity.MoveCallback != nil {
		status = entity.MoveCallback(done, reason)
	}

	m.clear(state, entity)
	MoveBehavior.StopMoveNotice(state.SceneId, entity.Id, entity.CurPos.ToVector2D(), status, entity.Direction.ToVector2D())
}

// getMoveTarget 获取当前移动目标点
func (m MoveSystem) getMoveTarget(state *schemas.MoveState, entity *schemas.MoveEntity) *math_utils.Vector2D {
	if m.isEmplyMoveTarget(state, entity) {
		return nil
	}

	if len(entity.MoveCirclePaths) > 0 {
		return &entity.MoveCirclePaths[0]
	}

	if len(entity.Paths) <= 0 {
		return nil
	}
	return &entity.Paths[0]
}

// isEmplyMoveTarget 检测移动目标点是否为空
func (m MoveSystem) isEmplyMoveTarget(state *schemas.MoveState, entity *schemas.MoveEntity) bool {
	return len(entity.Paths) <= 0 && len(entity.MoveCirclePaths) <= 0
}

// getPaths
func (m MoveSystem) getPaths(state *schemas.MoveState, entity *schemas.MoveEntity) []*common.Vector2D {
	paths := []*common.Vector2D{}
	for _, path := range entity.MoveCirclePaths {
		paths = append(paths, path.ToVector2D())
	}

	for _, path := range entity.Paths {
		paths = append(paths, path.ToVector2D())
	}
	return paths
}

// popMoveTarget 获取下次移动点
func (m MoveSystem) popMoveTarget(state *schemas.MoveState, entity *schemas.MoveEntity) bool {
	if len(entity.MoveCirclePaths) > 0 {
		entity.MoveCirclePaths = entity.MoveCirclePaths[1:]
		if len(entity.MoveCirclePaths) <= 0 && m.IsMoveCircle(state, entity) {
			entity.MoveStatus = common.MoveStatusType_MoveStatusMoving
		}

		m.setPropertyDirty(entity, common.MovePropertyType_PropertyMap)
		return true
	}

	if !m.popCurMoveTarget(state, entity) {
		return false
	}

	m.setPropertyDirty(entity, common.MovePropertyType_PropertyMap)
	return true
}

// updateMovePos 更新移动坐标
func (m MoveSystem) updateMovePos(state *schemas.MoveState, entity *schemas.MoveEntity, timePass math_utils.ZNumber) bool {
	curSpeed := entity.MoveSpeed
	if curSpeed.IsLq(0) {
		m.onStopMove(state, entity, false, move_defines.StopMoveReasonZeroSpeed)
		return false
	}

	curPos := entity.CurPos
	direction := entity.Direction
	isUpdate := false
	isStop := false

	for {
		if timePass.IsLq(0) || m.isEmplyMoveTarget(state, entity) {
			break
		}

		pos := m.getMoveTarget(state, entity)
		if pos == nil {
			m.onStopMove(state, entity, false, move_defines.StopMoveReasonUnknown)
			isStop = true
			break
		}

		targetPos := *pos
		isUpdate = true

		v := targetPos.Sub(curPos)
		if !v.IsZero() {
			direction = v
		}

		totalTimePass := v.Length().Dlv(curSpeed)
		if totalTimePass.Lq(timePass) {
			timePass = timePass.Sub(totalTimePass)
			curPos = targetPos
			if !m.popMoveTarget(state, entity) {
				m.onStopMove(state, entity, false, move_defines.StopMoveReasonUnknown)
				break
			}

			pathPos := m.getMoveTarget(state, entity)
			if pathPos != nil {
				MoveBehavior.UpdateMovePathNotice(state.SceneId, entity.Id, direction.ToVector2D(), curPos.ToVector2D(), pathPos.ToVector2D(), entity.PreCheckTime, m.getPaths(state, entity))
			}
		} else {
			curPos = curPos.Add(v.Normal().Mul(timePass).Mul(curSpeed))
			timePass.Value = 0
			break
		}
	}

	if isUpdate {
		entity.CurPos = curPos
		entity.Direction = direction
		m.setPropertyDirty(entity, common.MovePropertyType_PropertyMove)
	}

	if !isStop && m.isEmplyMoveTarget(state, entity) {
		m.onStopMove(state, entity, true, move_defines.StopMoveReasonSuccess)
	}
	return true
}

// handleMove 开始处理追击逻辑
func (m MoveSystem) handleFollow(state *schemas.MoveState, entity *schemas.MoveEntity) {
	aiEntity := state.GetBattleAIEntity(entity.Id)
	if aiEntity == nil {
		logger.ERR("追击查找实体失败1:", entity.Id)
		return
	}

	if aiEntity.TargetId != entity.FollowTargetId || aiEntity.Id != entity.Id {
		logger.ERR("追击实体目标错误2:", entity, " ", aiEntity)
		return
	}

	targetEntity := m.Find(state, aiEntity.TargetId)
	if targetEntity == nil {
		logger.ERR("追击查找实体失败3:", aiEntity.TargetId)
		return
	}

	noticeDist := math_utils.MakeZNumberByInt32(1)
	minDist := entity.Collision.Add(targetEntity.Collision)
	minDist = minDist.Add(noticeDist)
	minDistSquare := minDist.Mul(minDist)
	if !entity.IsFollowed && entity.IsNotice {
		dv := targetEntity.CurPos.Sub(entity.CurPos)
		if dv.LengthSquare().Me(minDistSquare) {
			entity.IsFollowed = true
			entity.IsNotice = false
		} else {
			logger.WARN("已经在攻击范围内，忽略追击行为:", entity.Id)
			return
		}
	}

	if !m.isEmplyMoveTarget(state, entity) {
		m.handleMove(state, entity)
		// logger.WARN("Id:", entity.Id, " ", " CurPos:", entity.CurPos, " TargetPos:", entity.TargetPos, " TargetCurPos:", targetEntity.CurPos)
	}

	cdv := entity.CurPos.Sub(targetEntity.CurPos)
	cdvls := cdv.LengthSquare()

	// 在攻击范围内，创建战斗
	if cdvls.Lq(minDistSquare) && !entity.IsNotice {
		logger.ERR("1 cdvls:", cdvls, " ", minDistSquare, " ", entity.CurPos, " ", targetEntity.CurPos)
		if entity.MoveCallback != nil {
			entity.MoveCallback(true, move_defines.StopMoveReasonSuccess)
			entity.IsNotice = true
		}
	}

	tv := entity.FollowTargetPos.Sub(targetEntity.CurPos)
	if tv.LengthSquare().IsMe(0) {
		entity.ResetTick++
	}

	baseDest := entity.MoveSpeed.Mul(math_utils.MakeByReal(500))
	moveDest := math_utils.MakeZNumberByInt64(30)

	if m.IsMoving(state, entity) || m.IsMoveCircle(state, entity) {
		if cdvls.Le(baseDest.Mul(baseDest)) || m.isEmplyMoveTarget(state, entity) {
			if entity.ResetTick > 1 {
				targetPos := m.CalcFollowPos(state, entity, targetEntity)
				if targetPos == nil {
					logger.ERR("追击计算目标错误失败:", entity)
					m.onStopMove(state, entity, false, move_defines.StopMoveReasonPathFindError)
					return
				}

				m.findPath(state, entity, entity.CurPos.ToVector2D(), targetPos)
				m.resetFollowTick(state, entity, targetEntity.CurPos)
				// logger.WARN("重置追击最新坐标_1:", entity.CurPos, " ", targetPos)
			}
		} else if cdvls.Lq(moveDest.Mul(moveDest)) && entity.ResetTick > 2 ||
			cdvls.Me(moveDest.Mul(moveDest)) && entity.ResetTick > 10 {
			targetPos := m.CalcFollowPos(state, entity, targetEntity)
			if targetPos == nil {
				logger.ERR("追击计算目标错误失败:", entity)
				m.onStopMove(state, entity, false, move_defines.StopMoveReasonPathFindError)
				return
			}

			m.findPath(state, entity, entity.CurPos.ToVector2D(), targetPos)
			m.resetFollowTick(state, entity, targetEntity.CurPos)
			// logger.WARN("重置追击最新坐标_2:", entity.CurPos, " ", targetPos)
		}
	}
}

// handleMove 开始处理移动逻辑
func (m MoveSystem) handleMove(state *schemas.MoveState, entity *schemas.MoveEntity) {
	curTime := time_tools.Now().UnixMilli()
	timePass := curTime - entity.PreCheckTime
	entity.PreCheckTime = curTime

	if timePass < 0 {
		m.onStopMove(state, entity, false, move_defines.StopMoveReasonUnknown)
		return
	}

	time := math_utils.MakeByReal(timePass)
	m.checkPreTown(state, entity)
	if time.IsMe(0) && (m.IsMoving(state, entity) || m.IsMoveCircle(state, entity)) {
		m.updateMovePos(state, entity, time)
	}
}

// ditryRefesh 脏数据同步
func (m MoveSystem) ditryRefesh(state *schemas.MoveState, entity *schemas.MoveEntity) {
	if !entity.IsDitry {
		return
	}

	entity.IsDitry = false
	syncData := []*common.SyncData{}
	for _, ditry := range entity.Ditry {
		var content []byte
		var err error
		if ditry.IsDitry {
			if ditry.Type == common.MovePropertyType_PropertyMove {
				moveData := &common.MoveData{
					CurPos:       entity.CurPos.ToVector2D(),
					Direction:    entity.Direction.ToVector2D(),
					UpdateMoveAt: entity.PreCheckTime,
				}

				content, err = moveData.Marshal()
				if err != nil {
					continue
				}
			} else if ditry.Type == common.MovePropertyType_PropertyMovePath {
				movePathData := &common.MovePathData{
					Paths: entity.MovePathData,
				}

				content, err = movePathData.Marshal()
				if err != nil {
					continue
				}
			} else if ditry.Type == common.MovePropertyType_PropertyMap {
				mapData := move_utils.MoveUtils.MakeMapData(state, entity)
				content, err = mapData.Marshal()
				if err != nil {
					continue
				}
			}

			syncData = append(syncData, &common.SyncData{
				Type:    ditry.Type,
				Content: string(content),
			})
		}
		ditry.IsDitry = false
	}
	MoveBehavior.SyncEntityData(state.SceneId, entity.Id, syncData)
}

// DitryTickerRefresh
func (m MoveSystem) DitryTickerRefresh(state *schemas.MoveState) error {
	state.Moving.Range(func(k, v interface{}) bool {
		entity := v.(*schemas.MoveEntity)
		if m.IsMoving(state, entity) || m.IsMoveCircle(state, entity) {
			m.ditryRefesh(state, entity)
		}
		return true
	})
	return nil
}

// TickerRefresh 刷新移动，处理所有移动行为
func (m MoveSystem) TickerMoveRefresh(state *schemas.MoveState) error {
	state.Moving.Range(func(k, v interface{}) bool {
		entity := v.(*schemas.MoveEntity)
		if m.IsMoving(state, entity) || m.IsMoveCircle(state, entity) {
			if entity.IsFollowMove {
				m.handleFollow(state, entity)
			} else {
				m.handleMove(state, entity)
			}
		}
		// 		logger.WARN("CurPos:", entity.CurPos, " TargetPos:", entity.TargetPos, " MoveCirclePaths:", entity.MoveCirclePaths, "Paths: ", entity.Paths)
		return true
	})
	return nil
}

// CalcFollowPos 计算目标的位置
func (m MoveSystem) CalcFollowPos(state *schemas.MoveState, entity *schemas.MoveEntity, targetEntity *schemas.MoveEntity) *common.Vector2D {
	dest := entity.Collision.Add(targetEntity.Collision)
	if targetEntity.CurPos.Sub(entity.CurPos).LengthSquare().Le(dest.Mul(dest)) {
		return entity.CurPos.ToVector2D()
	}

	ctx, ok := actors.MapIns.SharedReadOnlyCtx(parse.ToInt64(state.SceneId))
	if !ok {
		return nil
	}

	outPos, ok := move_utils.MoveUtils.CalcOutPos(ctx, entity.CurPos, entity.Collision, targetEntity.CurPos, targetEntity.Collision)
	if !ok {
		return nil
	} else {
		return outPos
	}
}

// CalcFollowNearPos
func (m MoveSystem) CalcFollowNearPos(state *schemas.MoveState, entity *schemas.MoveEntity, targetEntity *schemas.MoveEntity) *common.Vector2D {
	minDest := entity.Collision
	if !m.IsMoving(state, targetEntity) && !m.IsMoveCircle(state, targetEntity) {
		minDest = entity.Collision.Add(targetEntity.Collision)
	}

	if targetEntity.CurPos.Sub(entity.CurPos).LengthSquare().Le(minDest.Mul(minDest)) {
		return entity.CurPos.ToVector2D()
	}

	ctx, ok := actors.MapIns.SharedReadOnlyCtx(parse.ToInt64(state.SceneId))
	if !ok {
		return nil
	}

	outPos, ok := move_utils.MoveUtils.CalcOutPos(ctx, entity.CurPos, entity.Collision, targetEntity.CurPos, targetEntity.Collision)
	if !ok {
		return nil
	} else {
		return outPos
	}
}

func (m MoveSystem) resetFollowTick(state *schemas.MoveState, entity *schemas.MoveEntity, targetPos math_utils.Vector2D) {
	entity.ResetTick = 0
	entity.FollowTargetPos = targetPos
}

// MoveFollow 发起追击移动
func (m MoveSystem) MoveFollow(state *schemas.MoveState, entity *schemas.MoveEntity, targetEntity *schemas.MoveEntity,
	cb1 func(done bool, reason int32, value any),
	cb2 func(done bool, reason int32) bool) error {
	targetPos := m.CalcFollowPos(state, entity, targetEntity)
	if targetPos == nil {
		logger.ERR("追击计算目标错误:", entity, " ", targetEntity)
		return errors.New("计算目标点错误")
	}

	entity.IsFollowMove = true
	entity.IsNotice = false
	entity.IsFollowed = false
	entity.ResetTick = 0

	entity.MoveStatus = common.MoveStatusType_MoveStatusPathFind
	entity.FindPathCallback = cb1
	entity.MoveCallback = cb2
	entity.FollowTargetId = targetEntity.Id
	entity.FollowTargetPos = targetEntity.CurPos
	return m.findPath(state, entity, entity.CurPos.ToVector2D(), targetPos)
}

// CheckMoveTo 检测点位是否可以移动
func (m MoveSystem) CheckMoveTo(state *schemas.MoveState, pos math_utils.Vector2D) bool {
	ctx, ok := actors.MapIns.SharedReadOnlyCtx(parse.ToInt64(state.SceneId))
	if !ok {
		return false
	}

	if ctx.MapTerrain.IsBlock(pos.X.ToGrid(), pos.X.ToGrid()) {
		return false
	}
	return true
}

// MoveTo 发起移动
func (m MoveSystem) MoveTo(state *schemas.MoveState, entity *schemas.MoveEntity, targetPos *common.Vector2D,
	cb1 func(done bool, reason int32, value any), cb2 func(done bool, reason int32) bool) error {
	entity.MoveStatus = common.MoveStatusType_MoveStatusPathFind
	entity.FindPathCallback = cb1
	entity.MoveCallback = cb2

	entity.IsFollowMove = false
	entity.IsNotice = false
	entity.IsFollowed = false
	entity.ResetTick = 0
	return m.findPath(state, entity, entity.CurPos.ToVector2D(), targetPos)
}

// initPathFindData 初始化寻路点
func (m MoveSystem) initPathFindData(state *schemas.MoveState, entity *schemas.MoveEntity, paths []*common.Vector2D) error {
	if len(paths) > 1 {
		paths = paths[1:]
	}

	entity.MovePathData = []*common.Vector2D{}
	for _, path := range entity.MoveCirclePaths {
		entity.MovePathData = append(entity.MovePathData, path.ToVector2D())
	}

	entity.Paths = []math_utils.Vector2D{}
	for _, path := range paths {
		entity.Paths = append(entity.Paths, math_utils.MakeVector2dByProto(path))
	}

	entity.MovePathData = append(entity.MovePathData, paths...)
	if len(entity.Paths) > 0 {
		entity.TargetPos = entity.Paths[len(entity.Paths)-1]
	}

	m.setPropertyDirty(entity, common.MovePropertyType_PropertyMap)
	m.setPropertyDirty(entity, common.MovePropertyType_PropertyMovePath)

	// 发起寻路消息需要同步回复给客户端，不用做主动通知
	if entity.FindPathCallback != nil {
		entity.FindPathCallback(true, 0, entity)
		entity.FindPathCallback = nil
		return nil
	} else {
		moveData := &common.MoveData{
			CurPos:       entity.CurPos.ToVector2D(),
			UpdateMoveAt: entity.PreCheckTime,
			Direction:    entity.Direction.ToVector2D(),
		}

		if entity.MoveStatus != common.MoveStatusType_MoveStatusPathFind {
			moveData.UpdateMoveAt = entity.PreCheckTime
			return MoveBehavior.MovePathNotice(state.SceneId, entity.Id, entity.MovePathData, moveData)
		} else {
			moveData.UpdateMoveAt = time_tools.Now().UnixMilli()
			return MoveBehavior.MovePathNotice(state.SceneId, entity.Id, entity.MovePathData, moveData)
		}
	}
}

// startMoveInRegion 开始移动到某个区域
func (m MoveSystem) startMoveInRegion(state *schemas.MoveState, entity *schemas.MoveEntity) {
	entity.MoveStatus = common.MoveStatusType_MoveStatusMoving
	entity.PreCheckTime = time_tools.Now().UnixMilli()
	// state.AddMoving(entity.Id, entity)
}

// onPathFindResult 寻路结果
func (m MoveSystem) onPathFindResult(state *schemas.MoveState, entity *schemas.MoveEntity, paths []*common.Vector2D) error {
	if len(paths) <= 0 {
		m.onStopMove(state, entity, false, move_defines.StopMoveReasonPathFindError)
		return nil
	}

	err := m.initPathFindData(state, entity, paths)
	if err != nil {
		return err
	}

	if entity.MoveStatus == common.MoveStatusType_MoveStatusPathFind {
		m.startMoveInRegion(state, entity)
	}

	m.setPropertyDirty(entity, common.MovePropertyType_PropertyMap)
	return nil
}

// FindPath 向find_path_actor 发起寻路
func (m MoveSystem) findPath(state *schemas.MoveState, entity *schemas.MoveEntity, start *common.Vector2D, end *common.Vector2D) error {
	if err := actor.RpcAsyncCall(state.ActorId(), actor.GetServiceActorId("FindPath", state.SceneId),
		&rpc_protos.FindPathRpcGetPathsReq{
			Start: start,
			End:   end,
		}, func(ctx any, rsp any, err error) error {
			if fail := rpc_helper.RpcHelper.CheckFail(rsp, err); fail != nil {
				logger.ERR("FindPath failed: ", actor.GetServiceActorId("FindPath", state.SceneId), " fail: ", fail)
				if state.GetMoving(entity.Id) != nil {
					if m.IsMoving(state, entity) || m.IsMoveCircle(state, entity) {
						m.onStopMove(state, entity, false, move_defines.StopMoveReasonPathFindError)
					}
				} else {
					if entity.FindPathCallback != nil {
						entity.FindPathCallback(false, 0, nil)
						entity.FindPathCallback = nil
					} else {
						if entity.MoveCallback != nil {
							entity.MoveCallback(false, move_defines.StopMoveReasonPathFindError)
						}
					}
				}
				return nil
			}

			ret := rsp.(*rpc_protos.FindPathRpcGetPathsRsp)
			return m.onPathFindResult(state, entity, ret.Paths)
		}); err != nil {
		return err
	}
	return nil
}

// ChangeSpeed 改变移动速度
func (m MoveSystem) ChangeSpeed(state *schemas.MoveState, speed int32) {

}

type SortMapObjectData struct {
	Mo  *common.MapObject
	Cvt math_utils.Vector2D
}

// checkPreTown 检查移动是否有建筑碰撞绕路
func (m MoveSystem) checkPreTown(state *schemas.MoveState, entity *schemas.MoveEntity) {
	if entity.MoveStatus != common.MoveStatusType_MoveStatusMoving || len(entity.Paths) <= 0 ||
		len(entity.MoveCirclePaths) > 0 {
		return
	}

	curPos := entity.CurPos
	if len(entity.Paths) <= 0 {
		return
	}

	targetPos := entity.Paths[0]
	v := targetPos.Sub(curPos)

	checkPos := targetPos
	if v.LengthSquare().Me(math_utils.MakeZNumberByInt32(2 * math_defines.GridSize).Mul(math_utils.MakeZNumberByInt32(2 * math_defines.GridSize))) {
		checkPos = curPos.Add(v.Normal().Mul(math_utils.MakeZNumberByInt32(2 * math_defines.GridSize)))
	}

	if entity.PreCheckTownPos.X.IsMe(0) {
		dest := entity.PreCheckTownPos.Sub(checkPos)
		if dest.LengthSquare().Lq(math_utils.MakeZNumberByInt32(2 * math_defines.GridSize).Mul(math_utils.MakeZNumberByInt32(2 * math_defines.GridSize))) {
			return
		}
	}

	entity.PreCheckTownPos = checkPos
	ok, gridIndex := move_utils.MoveUtils.LineInterGrid(curPos, checkPos)
	if !ok {
		return
	}

	checkIdx := map[int64]int64{}
	collisionRelations := []SortMapObjectData{}

	for _, idx := range gridIndex {
		// mo := state.MapIndex[map_utils.MapUtils.PosToIdx(idx)]
		mo, _, err := map_system.Map.RpcFindByPos(parse.ToInt64(state.SceneId), idx)
		if err != nil {
			continue
		}

		if mo != nil && mo.Type == gd.GetGlobal().MapTypeTown {
			_, ok := checkIdx[mo.Id]
			if ok {
				continue
			}

			checkIdx[mo.Id] = mo.Id
			cl := move_utils.MoveUtils.GetCollision(mo)
			cvt := math_utils.Vector2D{}
			cld := cl.Sub(math_utils.MakeZNumberByFloat32(0.1))
			if move_utils.MoveUtils.IsRelation(curPos, targetPos, move_utils.MoveUtils.GetPosition(mo), cld, &cvt) {
				collisionRelations = append(collisionRelations, SortMapObjectData{Mo: mo, Cvt: cvt})
			}
		}
	}

	if len(collisionRelations) <= 0 {
		return
	}

	sort.SliceStable(collisionRelations, func(i, j int) bool {
		return collisionRelations[i].Cvt.LengthSquare().Le(collisionRelations[j].Cvt.LengthSquare())
	})

	startPos := curPos
	moveCriclePaths := []math_utils.Vector2D{}
	for _, check := range collisionRelations {
		cl := move_utils.MoveUtils.GetCollision(check.Mo).Add(entity.Collision)
		sl := move_utils.MoveUtils.GetScale(check.Mo)
		if cl.Me(sl) {
			cl = sl
		}

		result := move_utils.MoveUtils.CalMoveCriclePath(startPos, targetPos, move_utils.MoveUtils.GetPosition(check.Mo), cl, &moveCriclePaths)
		if result == move_defines.CalPathResultNone {
			continue
		}

		if len(moveCriclePaths) <= 0 {
			continue
		}

		if result == move_defines.CalPathResultPopTarget {
			m.popCurMoveTarget(state, entity)
		}

		entity.MoveCirclePaths = append(entity.MoveCirclePaths, moveCriclePaths...)
		break
	}

	if len(entity.MoveCirclePaths) > 0 {
		entity.MoveStatus = common.MoveStatusType_MoveStatusMoveCircle
		m.findPath(state, entity, entity.MoveCirclePaths[len(entity.MoveCirclePaths)-1].ToVector2D(), entity.TargetPos.ToVector2D())
		entity.PreCheckTownPos.SetRealValue(0, 0)
	}
}

// popCurMoveTarget
func (m MoveSystem) popCurMoveTarget(state *schemas.MoveState, entity *schemas.MoveEntity) bool {
	if len(entity.Paths) <= 0 {
		return false
	}

	entity.Paths = entity.Paths[1:]
	return true
}

// RpcGetMoveEntity
func (s MoveSystem) RpcGetMoveEntity(serverId, id int64) (*common.MoveData, bool) {
	logger.INFO("server id: ", serverId, ", line id: ", id)
	if state, ok := actors.MoveIns.SharedReadOnlyCtx(serverId); ok {
		entity := state.GetMoving(id)
		if entity != nil {
			return &common.MoveData{
				CurPos:       entity.CurPos.ToVector2D(),
				Direction:    entity.Direction.ToVector2D(),
				UpdateMoveAt: entity.PreCheckTime,
			}, true
		}
		return nil, false
	}

	actorId := actors.MapReaderId(serverId)
	rsp, err := actor.RpcCall(actorId, &rpc_protos.MoveRpcReaderGetMoveEntityReq{
		ServerId: serverId,
		Id:       id,
	})
	if fail := rpc_helper.RpcHelper.CheckFail(rsp, err); fail != nil {
		logger.ERR("get move behavior failed")
		return nil, false
	}
	ret := rsp.(*rpc_protos.MoveRpcReaderGetMoveEntityRsp)
	return ret.Data, ret.Ok
}
